package com.idanchuang.income;

import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.YearMonth;
import java.util.*;
import java.util.stream.Stream;

@Component
public class ServiceIncome {

    private BrandInfo brandInfo;
    private BrandMonthlyRateBuilder builder;


    public void createBuilder() throws Exception {
        InputStream inputStream = TableBuilder.class.getClassLoader().getResourceAsStream("builder.obs");
        try (ObjectInputStream input = new ObjectInputStream(inputStream)) {
            builder = (BrandMonthlyRateBuilder) input.readObject();
        }
    }


    /**
     * 获取用户每个品牌每种类型的收益
     *
     * @param userId
     * @param month
     * @param income
     * @return
     */
    public Map<String, BigDecimal[]> getOldUserMonthlyIncome(long userId, YearMonth month, BigDecimal income) {
        List<BrandInfo.BrandIncomeMonthlyRate> monthlyRate = builder.getMonthlyRate(userId, month);
        Map<String, BigDecimal[]> brandIncomes = new HashMap<>();
        for (BrandInfo.BrandIncomeMonthlyRate rate : monthlyRate) {
            BigDecimal brandIncome = rate.getRate().multiply(income);
            BigDecimal[] typeRates = rate.getTypeRates();
            BigDecimal[] incomes = new BigDecimal[typeRates.length];
            for (int i = 0; i < typeRates.length; i++) {
                incomes[i] = brandIncome.multiply(typeRates[i]);
            }
            brandIncomes.put(rate.getName(), incomes);
        }
        return brandIncomes;
    }

    /**
     * 获取用户每个品牌每种类型的收益
     *
     * @param userId
     * @param month
     * @param income
     * @return
     */
    public Map<String, BigDecimal[]> getUserMonthlyIncome(long userId, YearMonth month, BigDecimal income) {
        List<BrandInfo.BrandIncomeMonthlyRate> monthlyRate = builder.getMonthlyRate(userId, month);
        Map<String, BigDecimal[]> brandIncomes = new LinkedHashMap<>();

        for (BrandInfo.BrandIncomeMonthlyRate rate : monthlyRate) {
            BigDecimal sum = new BigDecimal(0);
            BigDecimal brandIncome = rate.getRate().multiply(income);
            BigDecimal[] typeRates = rate.getTypeRates();
            BigDecimal[] incomes = new BigDecimal[typeRates.length];
            StringJoiner joiner = new StringJoiner("\t");
            joiner.add(rate.getName());
            for (int i = 0; i < typeRates.length; i++) {
                sum = sum.add(typeRates[i]);
                incomes[i] = brandIncome.multiply(typeRates[i]);
                joiner.add(String.valueOf(typeRates[i].multiply(rate.getRate()).floatValue()));
            }
            brandIncomes.put(rate.getName(), incomes);
        }
        int baseIncome = 1000;
        String[] brands = monthlyRate.stream().sorted(Comparator.reverseOrder()).map(r -> r.getName()).toArray(String[]::new);
        Map<String, BigDecimal[]> newBrandIncomes = new LinkedHashMap<>();
        BigDecimal[] value = null;
        for (int i = 0, j = 0; i < brands.length && j < brands.length; j++) {
            BigDecimal[] bigDecimals = brandIncomes.get(brands[j]);
            value = merge(value, bigDecimals);
            if (sum(value).floatValue() < baseIncome && j < brands.length - 1) {
                continue;
            } else {
                if (j == brands.length - 1 && i > 1 && sum(value).floatValue() < baseIncome) {
                    BigDecimal[] preLast = newBrandIncomes.get(brands[i - 1]);
                    newBrandIncomes.put(brands[i - 1], merge(preLast, value));
                } else {
                    newBrandIncomes.put(brands[i], value);
                }
                i++;
                value = null;
            }
        }
        return newBrandIncomes;
    }

    private static BigDecimal[] merge(BigDecimal[] base, BigDecimal[] values) {
        if (base == null) {
            return clone(values);
        }
        for (int i = 0; i < values.length; i++) {
            base[i] = base[i].add(values[i]);
        }
        return base;
    }

    private static BigDecimal[] clone(BigDecimal[] values) {
        BigDecimal[] base = new BigDecimal[values.length];
        for (int i = 0; i < values.length; i++) {
            base[i] = values[i];
        }
        return base;
    }

    private static BigDecimal sum(BigDecimal... values) {
        return Stream.of(values).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    private static String[][] splitArray(String[] input, int count) {
        String[][] term = new String[count][];
        int len = input.length / count;
        for (int i = 0; i < count - 1; i++) {
            term[i] = Arrays.copyOfRange(input, i * len, (i + 1) * len);
        }
        term[count - 1] = Arrays.copyOfRange(input, (count - 1) * len, input.length);
        return term;
    }

    public static void main(String[] args) throws Exception {
        ServiceIncome serviceIncome = new ServiceIncome();
        serviceIncome.createBuilder();
//        printUserMonthIncoming(1053194, new float[]{41853.51F, 162352.80F, 238499.54F, 232728.15F, 144686.42F, 273815.41F, 186309.18F, 176520.12F, 198036.33F, 144668.13F, 1799469.59F});
        Map<String, BigDecimal[]> income = serviceIncome.getUserMonthlyIncome(200003, YearMonth.of(2020, 10), new BigDecimal(430.17F));
        double total = 0;
        for (String brand : income.keySet()) {
            StringJoiner joiner = new StringJoiner("\t");
            joiner.add(brand);
            BigDecimal[] v = income.get(brand);
            for (int i = 0; i < v.length; i++) {
                total += v[i].doubleValue();
                joiner.add(v[i].setScale(2, RoundingMode.HALF_UP).toString());
            }
            System.out.println(joiner.toString());
        }
        System.out.println("total=" + total);

    }

}
